# -*- coding = utf-8 -*-
# @Time : 2023/8/11 14:23
# @Author : 龙王赘婿_彪少
# @File : R200_power_control.py
# @Software: PyCharm

# 功能： R200 电源管理板测试


from socket import *
from threading import Thread
import struct
import time
import binascii

IP = "192.168.8.30"
PORT = 9000
# PORT = 9001
# PORT = 9002


class MYTCP:
    def __init__(self):
        self.ip = IP
        self.port = PORT
        self.client_socket = socket(AF_INET, SOCK_STREAM)
        self.client_socket.connect((self.ip, self.port))
        t1 = Thread(target=self.recv_thread)
        t2 = Thread(target=self.send_thread)
        t1.start()
        t2.start()
        t1.join()
        t2.join()
        self.client_socket.close()

    # 接收线程
    def recv_thread(self):
        while True:
            recv_data = self.client_socket.recv(1024)  # 最大接收1024字节
            self.print_recv_data(recv_data)
            # self.decode_heart(recv_data)
            # self.decode_battery(recv_data)
            # self.decode_status(recv_data)

    @staticmethod
    def print_recv_data(raw_data):
        print(f"recv：len = {len(raw_data)} data =", end=" ")
        for i in range(len(raw_data)):
            print(f"{raw_data[i]:02x}", end=" ")
        print()

    @staticmethod
    def decode_heart(raw_data):
        s = struct.Struct("<2B2H1I6B1H2B")
        up = s.unpack(raw_data)
        head = up[0]
        version = up[1]
        type = up[2]
        len = up[3]
        count = up[4]

        state = up[5]
        error = up[6]
        version1 = up[7]
        version2 = up[8]
        version3 = up[9]
        dynamic = up[10]

        crc = up[11]
        end1 = up[12]
        end2 = up[13]

        print(f"head = {head:02x} version = {version:02x} type = {type:04x} len = {len:04x} count = {count:08x}")

    @staticmethod
    def decode_battery(raw_data):
        s = struct.Struct("<2B2H1I2B6f1H2B")
        up = s.unpack(raw_data)
        head = up[0]
        version = up[1]
        type = up[2]
        len = up[3]
        count = up[4]

        charge_id = up[5]
        charge_flag = up[6]
        current = up[7]
        voltage = up[8]
        leave_power = up[9]
        sum_power = up[10]
        percent = up[11]
        temperature = up[12]

        crc = up[13]
        end1 = up[14]
        end2 = up[15]

        print(f"charge_id = {charge_id:02x} charge_flag = {charge_flag:02x}")
        print(f"current = {current:f} voltage = {voltage:f}")
        print(f"leave_power = {leave_power:f} sum_power = {sum_power:f}")
        print(f"percent = {percent:f} temperature = {temperature:f}")

    @staticmethod
    def decode_status(raw_data):
        s = struct.Struct("<2B2H1I8B1H2B")
        up = s.unpack(raw_data)
        head = up[0]
        version = up[1]
        type = up[2]
        len = up[3]
        count = up[4]

        s0 = up[5]
        s1 = up[6]
        s2 = up[7]
        s3 = up[8]
        s4 = up[9]
        s5 = up[10]
        s6 = up[11]
        s7 = up[12]

        crc = up[13]
        end1 = up[14]
        end2 = up[15]

    def send_switch(self):
        ptype = 0x30
        lenth = 16
        switch_type = 1
        switch_control = 1
        buf = [0xff, 0xfe, ptype, lenth, 0x00, switch_type, switch_control]
        s = struct.Struct("<2B2H1I2B")
        packed_data = s.pack(*buf)
        crc = self.crc16_cal(packed_data)
        crc_pack = struct.Struct('H').pack(crc)
        end = [0xfd, 0xfa]
        end_pack = struct.Struct("2B").pack(*end)
        packed_data = packed_data + crc_pack + end_pack
        return packed_data

    def send_led(self):
        ptype = 0x31
        lenth = 15
        state = 1
        buf = [0xff, 0xfe, ptype, lenth, 0x00, state]
        s = struct.Struct("<2B2H1I1B")
        packed_data = s.pack(*buf)
        crc = self.crc16_cal(packed_data)
        crc_pack = struct.Struct('H').pack(crc)
        end = [0xfd, 0xfa]
        end_pack = struct.Struct("2B").pack(*end)
        packed_data = packed_data + crc_pack + end_pack
        return packed_data

    def ackermann(self):
        mode = 1
        v = -0.5
        w = 0.5
        r = 0
        deg = 0
        buf = [0xff, 0xfe, 0x11, 31, 0x00, mode, v, w, r, deg]
        s = struct.Struct("<2B2H1I1B4f")
        packed_data = s.pack(*buf)
        crc = self.crc16_cal(packed_data)
        crc_pack = struct.Struct('H').pack(crc)
        end = [0xfd, 0xfa]
        end_pack = struct.Struct("2B").pack(*end)
        packed_data = packed_data + crc_pack + end_pack
        return packed_data

    @staticmethod
    def crc16_cal(datalist):
        # from "https://code84.com/461550.html"
        test_crc = 0xFFFF
        poly = 0xa001
        # poly=0x8005
        numl = len(datalist)
        for num in range(numl):
            data = datalist[num]
            test_crc = (data & 0xFF) ^ test_crc
            for bit in range(8):
                if (test_crc & 0x1) != 0:
                    test_crc >>= 1
                    test_crc ^= poly
                else:
                    test_crc >>= 1
        return test_crc

    # 发送线程
    def send_thread(self):
        while True:
            time.sleep(0.05)
            key = input("输入指令：")
            if key == "1":
                send_data = self.send_switch()
                n2 = binascii.b2a_hex(send_data)
                print(f"n2={n2},type={type(n2)}")
                self.client_socket.send(send_data)
            elif key == "2":
                send_data = self.send_led()
                n2 = binascii.b2a_hex(send_data)
                print(f"n2={n2},type={type(n2)}")
                self.client_socket.send(send_data)


if __name__ == "__main__":
    obj = MYTCP()

